package com.ecr.hub.service.destination.impl;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.annotation.Resource;

import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import com.ecr.hub.ApplicationException;
import com.ecr.hub.DestinationUnknownException;
import com.ecr.hub.model.destination.DestinationRailTranscoder;
import com.ecr.hub.service.destination.IDestinationManager;
import com.ecr.hub.service.destination.IDestinationRailTranscoder;

@Component("destinationRailTranscoder")
public class DestinationRailTranscoderImpl implements
		IDestinationRailTranscoder {

	// Dao pour les destinations.
	@Resource(name = "destinationManager")
	IDestinationManager destinationManager;

	// Liste des transcos.
	private Map<String, DestinationRailTranscoder> mapDestinationsRail;

	/**
	 * Problème de dernière minute. Il s'avère finnalement que nous n'avons plus
	 * la bijection 1 voie = 1 destination, mais nous pouvons avoir plusieurs
	 * destinations pour une voie. Plutôt que de changer le modèle de données à
	 * ce stade du développement (17/10/2011), on a simplement rajouté un champ
	 * texte dans la destination afin de pouvoir mettre une liste de codes
	 * destinations qui se rapportent à la destination éditée. Le corrolaire de
	 * ce "patch" est qu'il faut juste compléter la liste des correspondances
	 * destination / voie. (Pour l'instant la seule destination concernée est
	 * Forbach sur laquelle pointe une dizaine d'autres destinations).
	 * 
	 * On crée une map avec en clef l'id externe de la destination. Il peut y
	 * avoir plusieurs fois la même destination (plusieurs voies pour une même
	 * destination) mais ce n'est pas grave si la précédente clé est écrasée.
	 * L'important est de pouvoir positionner le wagon sur une des voies pour la
	 * destination. Par contre, lors de l'affectation par le coordinateur du
	 * programme de travail, on vérifie si la voie est disponible. Si elle ne
	 * l'est pas, on regarde à ce momment si d'autres voies correspondent à
	 * cette destination.
	 */
	private void buildMapDestinationRail() throws ApplicationException {

		try {
			// Récupération de la liste des transcos.
			List<DestinationRailTranscoder> lstDestinationsRail = destinationManager
					.getListDestinationsRail();
			// Instanciation de la map.
			mapDestinationsRail = new Hashtable<String, DestinationRailTranscoder>();
			// On itère dans la liste et on crée les correspondances avec en
			// plus la liste des ext ids.
			for (DestinationRailTranscoder destinationRailTranscoder : lstDestinationsRail) {
				mapDestinationsRail.put(
						destinationRailTranscoder.getDestinationExtId(),
						destinationRailTranscoder);

				// Si la destination a des destinations supplémentaires mappées
				// sur elle.
				if (destinationRailTranscoder.getLstDestinationsExtId() != null
						&& destinationRailTranscoder.getLstDestinationsExtId()
								.trim().length() > 0) {
					// On explose la liste des destinations suplémentaires.
					StringTokenizer strToken = new StringTokenizer(
							destinationRailTranscoder.getLstDestinationsExtId(),
							",");
					while (strToken.hasMoreElements()) {
						String destinationExtId = (String) strToken
								.nextElement();
						mapDestinationsRail.put(destinationExtId,
								destinationRailTranscoder);
					}
				}
			}
		} catch (DataAccessException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * A partir de la liste des destinations, récupère la voie associée.
	 */
	@Override
	public DestinationRailTranscoder getRailForDestination(
			String destinationExtId) throws ApplicationException {

		// Si la map n'a pas été créée , on effectue les recherches en base pour
		// sa création.
		if (mapDestinationsRail == null)
			buildMapDestinationRail();

		DestinationRailTranscoder transcoder = (DestinationRailTranscoder) mapDestinationsRail
				.get(destinationExtId);

		if (transcoder == null)
			throw new DestinationUnknownException(
					"Hub : Le code destination : " + destinationExtId
							+ " est inconnu");

		return transcoder;
	}

	/**
	 * Demande de rafraîchissement du tableau de correspondance entre la liste
	 * des destinations et les voies associées. Onefface simplement la map des
	 * correspondances.
	 */
	public void refresh() {
		mapDestinationsRail = null;
	}
}
